﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// moniter wait for input event from InputControlCenter
using System;

public enum JageResult
{
	Unknown,
	Perfect,
	Good,
	Fail,
}

public class JudgmentMonitor
{
	public JudgmentMonitor()
	{

	}

	private float ticker;
	public float Ticker
	{
		get
		{
			return ticker;
		}
		set
		{
			ticker = value;
		}
	}

	private InputAction inputAct;
	public InputAction Act
	{
		get {return inputAct;}
		set {inputAct = value;}
	}
}

public class PrsJdgEventArgs : EventArgs
{
	public JageResult jgRst;
}

public class PressJudgment : MonoBehaviour {
	public InputControlCenter inputCtrl;
	public delegate void PlayResult();
	public event EventHandler<PrsJdgEventArgs> evtPrsJdg;
	private KeyValuePair<float, JageResult>[] resultMap;
	protected List<JudgmentMonitor> monitorList;
	public UILabel label1;
	public UILabel label2;
	public UILabel label3;
	public float good_error_allowed;
	public float fail_error_allowed;
	
	// Use this for initialization
	void Start () {
		resultMap = new KeyValuePair<float, JageResult>[5]{
			new KeyValuePair<float, JageResult> (0.0f, JageResult.Good),
			new KeyValuePair<float, JageResult> (fail_error_allowed - good_error_allowed, JageResult.Perfect),
			new KeyValuePair<float, JageResult> (fail_error_allowed + good_error_allowed, JageResult.Perfect),
			new KeyValuePair<float, JageResult> (fail_error_allowed * 2, JageResult.Good),
			new KeyValuePair<float, JageResult> (fail_error_allowed * 4, JageResult.Fail)
		}; 

		monitorList = new List<JudgmentMonitor> ();

		inputCtrl.evtUserInput += new System.EventHandler<InputEventArgs> (OnInputEvent);
	}
	
	// Update is called once per frame
	void Update () {
		for (int i = monitorList.Count - 1; i >= 0; i--) 
		{
			JudgmentMonitor jm = monitorList[i];
			jm.Ticker += Time.deltaTime;
			
			// 超过了failed的时间极限就直接判定演奏失败
			if (jm.Ticker > resultMap[resultMap.GetLength(0) - 2].Key) 
			{
				if(null != evtPrsJdg)
				{
					PrsJdgEventArgs jdgArgs = new PrsJdgEventArgs();
					jdgArgs.jgRst = resultMap[resultMap.GetLength(0) - 1].Value;
					evtPrsJdg(this, jdgArgs);
				}

				monitorList.RemoveAt(i);
			}
		}

		DebugView ();
	}

	void DebugView() 
	{
		if(!label1 || !label2 || !!label3)
			return ;

		label1.enabled = false;
		label2.enabled = false;
		label3.enabled = false;
		foreach(JudgmentMonitor jm in monitorList)
		{
			if(jm.Act == InputAction.PressDown)
			{
				label1.text = jm.Ticker.ToString();
				label1.enabled = true;
			}
			
			if(jm.Act == InputAction.RaiseUp)
			{
				label2.text = jm.Ticker.ToString();
				label2.enabled = true;
			}
			
			if(jm.Act == InputAction.SliderUp)
			{
				label3.text = jm.Ticker.ToString();
				label3.enabled = true;
			}
		}
	}

	public void BeginAnalysis (InputAction type)
	{
		JudgmentMonitor tmp = new JudgmentMonitor();
		tmp.Act = type;
		monitorList.Add(tmp);
	}

	public void OnInputEvent(object send, InputEventArgs args)
	{
		bool check = false;
		
		foreach(JudgmentMonitor jm in monitorList)
		{
			check = CheckJMResult(jm, args.Action);
			if(check)
			{
				if(!monitorList.Remove(jm))
				{
					Debug.LogError("JMonitor can not remove!");
				}
				break;
			}
		}
		
		// 来路不明的按键直接判负
		if (!check)
		{
			Debug.Log("User UnCatched Input: " + args.Action.ToString());
			PrsJdgEventArgs jdgArgs = new PrsJdgEventArgs();
			jdgArgs.jgRst = JageResult.Unknown;
			
			if(null != evtPrsJdg)
				evtPrsJdg(this, jdgArgs);
		}
	}

	public bool IsEmpty()
	{
		return monitorList.Count == 0;
	}

	public void RemoveAllJMonitor()
	{
		monitorList.Clear ();
	}

	bool CheckJMResult(JudgmentMonitor jmonitor, InputAction args)
	{
		if(jmonitor.Act != args)
			return false;

		bool findMonitor = false;

		for (int i = 0; i < resultMap.GetLength(0) - 1; ++i) {
			if(jmonitor.Ticker > resultMap[i].Key &&
			   jmonitor.Ticker < resultMap[i + 1].Key)
			{
				if(null != evtPrsJdg)
				{
					PrsJdgEventArgs jdgArgs = new PrsJdgEventArgs();
					jdgArgs.jgRst = resultMap[i].Value;
					evtPrsJdg(this, jdgArgs);
				}

				findMonitor = true;
			}
		}
		
		return findMonitor;
	}
}
